/*
 * $Id: MainApp.cc,v 1.15 2007/06/21 11:12:45 baconevi Exp $
 */

#include "Globals.h"
#include "MainApp.h"
#include <xp/bas/MutexLock.hpp>

MainApp::MainApp (): tcp_gate (XP_T("tcp_gate"))
{
	ret_code = 0;
	stop_requested = false;
}

MainApp::~MainApp () 
{
}
    
int MainApp::run ()
{
	if (Socket::startup () == -1) 
	{
		XP_LOG0 (&app_log, XP_NULL, XP_LOG_CRITICAL, 
			XP_T("cannot start up socket subsystem"));
		return -1;
	}

	stop_requested = false;

	XP_LOG0 (&app_log, XP_NULL, XP_LOG_INFO, XP_T("started"));
	run_main_task ();
	XP_LOG0 (&app_log, XP_NULL, XP_LOG_INFO, XP_T("exiting"));

	Socket::cleanup ();
	return 0;
}

int MainApp::stop ()
{
	return stopWithCode (0);
}

int MainApp::stopWithCode (int code)
{
	MutexLock lock (&startup_mutex);
	int n = 0;

	ret_code = code;
	if (tcp_gate.stop () == -1) n = -1;

	stop_requested = true;

	return n;
}

int MainApp::run_main_task (void)
{
	bool gate_enable_tcp;
	bool gate_tcp_local_only;
	xp_char_t gate_tcp_service[TcpAddress::MAX_SERVICE_LEN + 1];

	bool old_gate_enable_tcp = false;
	bool old_gate_tcp_local_only = false;
	xp_char_t old_gate_tcp_service[xp_countof(gate_tcp_service)] = { XP_T('\0') };

#ifdef _WIN32
	HANDLE quitEvent = OpenEvent (
		EVENT_ALL_ACCESS, FALSE, APP_EVENT_NAME);
	if (quitEvent == INVALID_HANDLE_VALUE)
	{
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
			XP_T("cannot open the event - %s"),
			APP_EVENT_NAME);
			
		stopWithCode (1);
		goto exit_main_task;
	}
#endif

	while (!stop_requested) 
	{
		{
			MutexLock lock (&app_env_mutex);
			gate_enable_tcp = app_env.gateEnableTcp ();
			gate_tcp_local_only = app_env.gateTcpLocalOnly ();
			xp_strxcpy (gate_tcp_service, 
				xp_countof(gate_tcp_service), app_env.gateTcpService());
		}

		if (gate_enable_tcp) 
		{ 
			if (gate_enable_tcp != old_gate_enable_tcp ||
			    gate_tcp_local_only != old_gate_tcp_local_only ||
			    xp_strcmp(gate_tcp_service, old_gate_tcp_service) != 0 ||
			    tcp_gate.state() != Thread::RUNNING) 
			{
				// disabled to enabled and/or tcp_local_only changed. 
				if (old_gate_enable_tcp && tcp_gate.stop() == -1) {
					XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
						XP_T("cannot stop %s"), tcp_gate.name());
					stopWithCode (1);
					break;
				}
				if (old_gate_enable_tcp && tcp_gate.join() == -1) {
					XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
						XP_T("cannot join %s"), tcp_gate.name());
					stopWithCode (1);
					break;
				}

				TcpAddress addr;
				if (TcpAddress::resolve (gate_tcp_service,
					(gate_tcp_local_only? XP_T(""): XP_NULL), &addr) == -1) {
					XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
						XP_T("cannot resolve the service - %s"),
						gate_tcp_service);
				}
				else 
				{
					tcp_gate.setBindingAddress (addr);
		
					MutexLock lock (&startup_mutex);
					if (stop_requested) break;

					if (tcp_gate.start() == -1) 
					{
						XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
							XP_T("cannot start the service - %s"), 
							tcp_gate.name());
					}
				}
			}
		}
		else if (gate_enable_tcp != old_gate_enable_tcp) 
		{
			// enabled -> disabled
			if (tcp_gate.stop() == -1) {
				XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
					XP_T("cannot stop %s"), tcp_gate.name());
				stopWithCode (1);
				break;
			}
			if (tcp_gate.join() == -1) {
				XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
					XP_T("cannot join %s"), tcp_gate.name());
				stopWithCode (1);
				break;
			}
		}

		old_gate_enable_tcp = gate_enable_tcp;
		old_gate_tcp_local_only = gate_tcp_local_only;
		xp_strxcpy (old_gate_tcp_service,
			xp_countof(old_gate_tcp_service), gate_tcp_service);

	#ifdef _WIN32
		if (WaitForSingleObject (quitEvent, 1000) == WAIT_OBJECT_0)
		{
			stop ();
		}
	#else
		// TODO: condition_timed_wait would be a better way.
		xp_sleep (1000);
	#endif
	}

#ifdef _WIN32
	CloseHandle (quitEvent);

exit_main_task:
#endif
	tcp_gate.join ();
	return 0;
}


